package com.honeybee.cloud.framework.common.aop;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 操作日志记录处理
 *
 * @author edi
 */
@Slf4j
@SuppressWarnings("all")
public abstract class AbstractLogAspect {

    /**
     * 配置日志织入点
     */
    @Pointcut("@annotation(com.honeybee.cloud.framework.common.aop.Log)")
    public void entryPoint() {
    }

    @Around("entryPoint()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object result = print(joinPoint, request);
        return result;

    }

    protected Object print(ProceedingJoinPoint joinPoint, HttpServletRequest request) throws Throwable {

        // ProceedingJoinPoint 为JoinPoint 的子类，在父类基础上多了proceed()方法，用于增强切面
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //java reflect相关类，通过反射得到注解
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        Log log = method.getAnnotation(Log.class);
        //描述
        String description = null;
        if (Objects.nonNull(log)) {
            //描述
            description = log.name();
        }
        //拼凑目标类名和参数名
        Object[] objects = joinPoint.getArgs();
        List<Object> paramList = Lists.newArrayList();
        // 此三类型一般不是参数
        if (objects != null) {
            for (Object object : objects) {
                if (object instanceof HttpServletRequest) {
                    continue;
                }
                if (object instanceof MultipartFile) {
                    continue;
                }
                if (object instanceof HttpServletResponse) {
                    continue;
                }
                paramList.add(object);
            }
        }
        String params = JSONArray.toJSONString(paramList);
        String requestParams = JSONObject.toJSONString(params);
        AbstractLogAspect.log.info("开始调用--> {} 参数:{}", description, requestParams);
        Object result = joinPoint.proceed();
        String response = JSONObject.toJSONString(result);
        AbstractLogAspect.log.info("调用结束<-- {} 返回值:{}", description, response);
        return result;
    }

}
